import { Provide, Inject } from '@midwayjs/core';
import { Context } from '@midwayjs/koa';
import { CaptchaService } from '@midwayjs/captcha';
import { JwtService } from '@midwayjs/jwt'; // 鉴权和校验
import { LoginDTO } from '@dto/login.dto'; // 登录参数格式
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { UserEntity } from '@entity/system/user.entity';
import { LoginInforEntity } from '@entity/monitor/loginInfor.entity';
import { isEqualPsw } from '@/utils/password';
import { resBuild } from '@utils/resBuild';
import { formatDate } from '@utils/time';
import { getIp } from '@/utils/device';
import * as useragent from 'useragent';
import { HttpService } from '@midwayjs/axios';
import { RedisService } from '@midwayjs/redis';
import { RedisEnum } from '@utils/enum';
import { Decrypt } from '@/utils/aes';

@Provide()
export class LoginService {
  @Inject()
  ctx: Context;

  @Inject()
  captchaService: CaptchaService;

  @Inject()
  jwtService: JwtService;

  @Inject()
  httpService: HttpService;

  @Inject()
  redisService: RedisService;

  @InjectEntityModel(UserEntity)
  userEntity: Repository<UserEntity>;

  @InjectEntityModel(LoginInforEntity)
  loginInforEntity: Repository<LoginInforEntity>;

  // 生成验证码
  async captchaImage() {
    const temp = await this.redisService.get(
      `${RedisEnum.SYS_CONFIG_KEY}sys.account.captchaEnabled`
    );
    const isCaptchaEnabled = temp === null ? true : JSON.parse(temp);
    if (JSON.parse(isCaptchaEnabled)) {
      // 如果开启了验证码，则生成验证码
      const { id, imageBase64 } = await this.captchaService.formula({
        noise: 1,
      }); // noise是干扰项条数，具体配置可看文档
      // 把校验id存起来，和后面的登录时的参数、对比值是否一致
      this.ctx.session.codeId = id;
      return {
        code: 200,
        msg: '操作成功',
        img: imageBase64, // 此处直接返回base64图片，和若依的base64位字符串不一样
        captchaEnabled: isCaptchaEnabled, // 是否开启验证码校验
      };
    } else {
      // 如果关闭了验证码，则返回captchaEnabled值为false
      return resBuild.more({
        captchaEnabled: isCaptchaEnabled, // 是否开启验证码校验
      });
    }
  }

  // 登录接口
  async login(body: LoginDTO) {
    try {
      const { username, password, code } = body;

      // 查询用户信息
      const userInfoTemp: UserEntity = await this.userEntity.findOne({
        where: {
          userName: username,
        },
      });

      // 移除所有日志记录相关代码
      // 不再检查登录日志配置，也不执行recordLog

      // 验证用户是否存在
      if (!userInfoTemp) {
        throw new Error('用户不存在');
      }

      // 验证码验证（如果开启）
      if (this.ctx.session.isCaptchaEnabled) {
        const isEqualCode: boolean = await this.captchaService.check(
          this.ctx.session.codeId,
          code
        );
        if (!isEqualCode) {
          throw new Error('验证码错误');
        }
      }

      // 密码验证
      if (!password || typeof password !== 'string') {
        throw new Error('密码格式无效');
      }

      if (!userInfoTemp.password) {
        throw new Error('用户密码不存在');
      }

      const isEqualPswFlag: boolean = await isEqualPsw(
        password,
        userInfoTemp.password.trim()
      );

      if (!isEqualPswFlag) {
        throw new Error('账号或密码错误');
      }

      // 生成并设置token
      this.ctx.session.userInfo = userInfoTemp;
      const token: string = await this.jwtService.sign({
        userId: userInfoTemp.userId,
        username: userInfoTemp.userName,
      });

      this.ctx.cookies.set('token', token, {
        maxAge: 24 * 60 * 60 * 1000,
        httpOnly: true,
        signed: true,
        overwrite: true,
      });

      return resBuild.more({
        token: token,
      });
    } catch (error) {
      this.ctx.logger.error('登录过程出错:', error);
      const errorMessage = error instanceof Error ? error.message : '登录失败，请稍后重试';
      this.ctx.status = 200;
      throw new Error(errorMessage);
    }
  }

  /** 退出登录 */
  async logout() {
    this.ctx.cookies.set('token', '', {
      maxAge: 0, // 0表示立即过期
      httpOnly: true, // 只能通过 HTTP 请求访问，不能通过 JavaScript 访问
      signed: true, // 签名 cookie，防止篡改
      overwrite: true, // 如果已有同名 cookie，则覆盖
    });
    this.ctx.session.userInfo = null;
    return resBuild.success();
  }

  // 记录登录日志
  async recordLog(username: string) {
    const webAgent = this.ctx.request.header['user-agent'];

    const temp = await this.redisService.get(
      `${RedisEnum.SYS_CONFIG_KEY}sys.interface.enable`
    );
    const isOpenCrypt = temp === null ? true : JSON.parse(temp);

    const body: any = isOpenCrypt
      ? JSON.parse(Decrypt(this.ctx.response.body))
      : this.ctx.response.body;
    const ip = getIp(this.ctx);
    let loginLocation = '';

    // 如果拆分后长度为4，则是ipv4地址，且不带::本地
    if (ip && !ip.includes('::') && ip.split('.').length === 4) {
      // 如果拆分后长度为4，则是ipv4地址，且不带::本地
      if (ip && !ip.includes('::') && ip.split('.').length === 4) {
        const tempIpInfo = await this.httpService.get(
          `https://opendata.baidu.com/api.php?query=${ip}&co=&resource_id=6006&oe=utf8`
        );
        loginLocation = `${tempIpInfo.data.data[0].location}`
          .replace('省', ' ')
          .replace('市', '');
      }
    }

    if (webAgent) {
      const myAgent = useragent.parse(this.ctx.request.header['user-agent']);
      const os = myAgent.os.toJSON().family;
      const browser = myAgent.toAgent();

      // 登录时记录登录日志
      const logData = {
        userName: username,
        ipaddr: ip,
        loginLocation,
        browser,
        os,
        status: body?.code === 200 ? '0' : '1',
        msg: body?.msg || '',
        loginTime: formatDate(new Date()),
      };

      const tempEntity: any = this.loginInforEntity.create(logData);
      await this.loginInforEntity.save(tempEntity);
    } else {
      // 登录时记录登录日志
      const logData = {
        userName: username,
        ipaddr: ip,
        loginLocation,
        browser: null,
        os: null,
        status: body?.code === 200 ? '0' : '1',
        msg: body?.msg || '',
        loginTime: formatDate(new Date()),
      };

      const tempEntity: any = this.loginInforEntity.create(logData);
      await this.loginInforEntity.save(tempEntity);
    }
  }
}
